//
//  ZFPlayerView.h
//
//  LajinLive
//
//  Created by 刘洋 on 2016/10/20.
//  Copyright © 2016年 lajin. All rights reserved.
//

#import "LJZFPlayerView.h"
#import "UIView+CustomControlView.h"
#import <MediaPlayer/MediaPlayer.h>
#import "LJZFPlayerControlView.h"
#import "IGNetReachable.h"

// 枚举值，包含水平移动方向和垂直移动方向
typedef NS_ENUM(NSInteger, PanDirection){
    PanDirectionHorizontalMoved, // 横向移动
    PanDirectionVerticalMoved    // 纵向移动
};

// 播放器的几种状态
typedef NS_ENUM(NSInteger, ZFPlayerState) {
    ZFPlayerStateFailed,     // 播放失败
    ZFPlayerStateBuffering,  // 缓冲中
    ZFPlayerStatePlaying,    // 播放中
    ZFPlayerStateStopped,    // 停止播放
    ZFPlayerStatePause       // 暂停播放
};

@interface LJZFPlayerView () <UIGestureRecognizerDelegate, UIAlertViewDelegate>

@property (nonatomic, strong) AVPlayerItem           *playerItem;
@property (nonatomic, strong) AVURLAsset             *urlAsset;
@property (nonatomic, strong) AVAssetImageGenerator  *imageGenerator;
/** playerLayer */
@property (nonatomic, strong) AVPlayerLayer          *playerLayer;
@property (nonatomic, strong) id                     timeObserve;
/** 滑杆 */
@property (nonatomic, strong) UISlider               *volumeViewSlider;
/** 用来保存快进的总时长 */
@property (nonatomic, assign) CGFloat                sumTime;
/** 定义一个实例变量，保存枚举值 */
@property (nonatomic, assign) PanDirection           panDirection;
/** 播发器的几种状态 */
@property (nonatomic, assign) ZFPlayerState          state;
/** 是否在调节音量*/
@property (nonatomic, assign) BOOL                   isVolume;
/** slider上次的值 */
@property (nonatomic, assign) CGFloat                sliderLastValue;
/** 进入后台*/
@property (nonatomic, assign) BOOL                   didEnterBackground;
/** 单机屏幕事件 */
@property (nonatomic, strong) UITapGestureRecognizer *singleTap;
/** 视频覆盖在此imageView上 */
@property (nonatomic, strong) UIImageView            *imageView;
/** 是否是本地视频 */
@property (nonatomic, assign) BOOL isLocalVideo;

@end

@implementation LJZFPlayerView

#pragma mark - life Cycle

/**
 *  代码初始化调用此方法
 */
- (instancetype)init
{
    self = [super init];
    if (self) {
        self.isFullScreen = NO;
        [[NSUserDefaults standardUserDefaults] removeObjectForKey:@"isFirstChangeToWWAN"];
        // 网络状态监控
        [[NSNotificationCenter defaultCenter] addObserver:self
                                                 selector:@selector(reachabilityChanged:)
                                                     name:AFNetworkingReachabilityDidChangeNotification
                                                   object:nil];
        //监听物理按键
        [[AVAudioSession sharedInstance] addObserver:self
                                          forKeyPath:@"outputVolume"
                                             options:NSKeyValueObservingOptionNew | NSKeyValueObservingOptionOld
                                             context:(void *)[AVAudioSession sharedInstance]];
    }
    return self;
}

- (void)dealloc
{
    self.playerItem = nil;
    [self.controlView zf_playerCancelAutoFadeOutControlView];
    // 移除通知
    [[NSNotificationCenter defaultCenter] removeObserver:self];
    [[AVAudioSession sharedInstance] removeObserver:self forKeyPath:@"outputVolume"];
    // 移除time观察者
    if (self.timeObserve) {
        [self.player removeTimeObserver:self.timeObserve];
        self.timeObserve = nil;
    }
}

#pragma mark - 观察者、通知

/**
 *  添加观察者、通知
 */
- (void)addNotifications
{
    // app退到后台
    [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(appDidEnterBackground) name:UIApplicationWillResignActiveNotification object:nil];
    // app进入前台
    [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(appDidEnterPlayground) name:UIApplicationDidBecomeActiveNotification object:nil];
}

#pragma mark - layoutSubviews

- (void)layoutSubviews
{
    [super layoutSubviews];
    self.playerLayer.frame = self.bounds;
    [self layoutIfNeeded];
}

/** 设置Player相关参数 */
- (void)configZFPlayer
{
    NSURL *videoUrl = [NSURL URLWithString:self.playerModel.videoUrl];
    self.urlAsset = [AVURLAsset assetWithURL:videoUrl];
    // 初始化playerItem
    self.playerItem = [AVPlayerItem playerItemWithAsset:self.urlAsset];
    // 每次都重新创建Player，替换replaceCurrentItemWithPlayerItem:，该方法阻塞线程
    self.player = [AVPlayer playerWithPlayerItem:self.playerItem];
    // 初始化playerLayer
    self.playerLayer = [AVPlayerLayer playerLayerWithPlayer:self.player];
    // 此处为默认视频填充模式
    self.playerLayer.videoGravity = AVLayerVideoGravityResizeAspect;
    // 添加playerLayer到self.layer
    [self.layer insertSublayer:self.playerLayer atIndex:0];
    // 添加播放进度计时器
    [self createTimer];
    // 获取系统音量
    [self configureVolume];
    self.videoNetStatusing = LJVideoNetStatusNormal;
    
    // 本地文件不设置ZFPlayerStateBuffering状态
    if ([videoUrl.scheme isEqualToString:@"file"]) {
        self.state = ZFPlayerStatePlaying;
        self.isLocalVideo = YES;
        // 开始播放
        [self play];
        self.isPauseByUser = NO;
        
        // 强制让系统调用layoutSubviews 两个方法必须同时写
        [self setNeedsLayout]; //是标记 异步刷新 会调但是慢
        [self layoutIfNeeded]; //加上此代码立刻刷新

        [[NSNotificationCenter defaultCenter] removeObserver:self name:AFNetworkingReachabilityDidChangeNotification object:nil];
    } else {
        self.state = ZFPlayerStateBuffering;
        self.isLocalVideo = NO;
        [self.controlView zf_playerDownloadBtnState:YES];
        // 开始播放
        [self play];
        self.isPauseByUser = NO;
        
        // 强制让系统调用layoutSubviews 两个方法必须同时写
        [self setNeedsLayout]; //是标记 异步刷新 会调但是慢
        [self layoutIfNeeded]; //加上此代码立刻刷新
        
        //首次流量播放的时候提示
        if (![[NSUserDefaults standardUserDefaults] objectForKey:@"isFirstChangeToWWAN"]) {
            [self reachabilityChanged:@"1"];
        }
    }
}

/** 自动播放，默认不自动播放 */
- (void)autoPlayTheVideo
{
    // 设置Player相关参数
    [self configZFPlayer];
}

/** 创建手势 */
- (void)createGesture
{
    // 单击
    self.singleTap = [[UITapGestureRecognizer alloc]initWithTarget:self action:@selector(singleTapAction:)];
    self.singleTap.delegate                = self;
    [self addGestureRecognizer:self.singleTap];
    
    // 解决点击当前view时候响应其他控件事件
    [self.singleTap setDelaysTouchesBegan:YES];
}

- (void)createTimer
{
    __weak typeof(self) weakSelf = self;
    self.timeObserve = [self.player addPeriodicTimeObserverForInterval:CMTimeMakeWithSeconds(1, 1) queue:nil usingBlock:^(CMTime time){
        AVPlayerItem *currentItem = weakSelf.playerItem;
        NSArray *loadedRanges = currentItem.seekableTimeRanges;
        if (loadedRanges.count > 0 && currentItem.duration.timescale != 0) {
            NSInteger currentTime = (NSInteger)CMTimeGetSeconds([currentItem currentTime]);
            CGFloat totalTime     = (CGFloat)currentItem.duration.value / currentItem.duration.timescale;
            CGFloat value         = CMTimeGetSeconds([currentItem currentTime]) / totalTime;
            [weakSelf.controlView zf_playerCurrentTime:currentTime totalTime:totalTime sliderValue:value];
        }
    }];
}

/** 获取系统音量 */
- (void)configureVolume
{
    MPVolumeView *volumeView = [[MPVolumeView alloc] init];
    _volumeViewSlider = nil;
    for (UIView *view in [volumeView subviews]){
        if ([view.class.description isEqualToString:@"MPVolumeSlider"]){
            _volumeViewSlider = (UISlider *)view;
            break;
        }
    }
    
//    /** 隐藏系统音量框的核心代码 ==begin== */
//    [self addSubview:_volumeViewSlider];
//    _volumeViewSlider.hidden = YES;
//    [_volumeViewSlider setFrame:CGRectMake(-1000, -1000, 100, 100)];
//    /** 隐藏系统音量框的核心代码 ==end== */
 
    // 使用这个category的应用不会随着手机静音键打开而静音，可在手机静音下播放声音
    NSError *setCategoryError = nil;
    BOOL success = [[AVAudioSession sharedInstance]
                    setCategory: AVAudioSessionCategoryPlayback
                    error: &setCategoryError];
    
    if (!success) { /* handle the error in setCategoryError */ }
    
    // 监听耳机插入和拔掉通知
    [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(audioRouteChangeListenerCallback:) name:AVAudioSessionRouteChangeNotification object:nil];
}

/**
 *  耳机插入、拔出事件
 */
- (void)audioRouteChangeListenerCallback:(NSNotification*)notification
{
    NSDictionary *interuptionDict = notification.userInfo;
    
    NSInteger routeChangeReason = [[interuptionDict valueForKey:AVAudioSessionRouteChangeReasonKey] integerValue];
    
    switch (routeChangeReason) {
            
        case AVAudioSessionRouteChangeReasonNewDeviceAvailable:
            // 耳机插入
            break;
            
        case AVAudioSessionRouteChangeReasonOldDeviceUnavailable:
        {
            // 耳机拔掉
            // 拔掉耳机继续播放
            [self play];
        }
            break;
            
        case AVAudioSessionRouteChangeReasonCategoryChange:
            // called at start - also when other audio wants to play
            NSLog(@"AVAudioSessionRouteChangeReasonCategoryChange");
            break;
    }
}

#pragma mark - KVO

- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context
{
    if (object == self.player.currentItem) {
        if ([keyPath isEqualToString:@"status"]) {
            
            if (self.player.currentItem.status == AVPlayerItemStatusReadyToPlay) {
                [self.controlView zf_playerEnableFullScreenBtn:YES];
                self.state = ZFPlayerStatePlaying;
                // 加载完成后，再添加平移手势
                // 添加平移手势，用来控制音量、亮度、快进快退
                UIPanGestureRecognizer *panRecognizer = [[UIPanGestureRecognizer alloc]initWithTarget:self action:@selector(panDirection:)];
                panRecognizer.delegate = self;
                [panRecognizer setMaximumNumberOfTouches:1];
                [panRecognizer setDelaysTouchesBegan:YES];
                [panRecognizer setDelaysTouchesEnded:YES];
                [panRecognizer setCancelsTouchesInView:YES];
                [self addGestureRecognizer:panRecognizer];
                
                // 跳到xx秒播放视频
                if (self.seekTime) {
                    [self seekToTime:self.seekTime completionHandler:nil];
                }
                
            } else if (self.player.currentItem.status == AVPlayerItemStatusFailed) {
                self.state = ZFPlayerStateFailed;
            }
        } else if ([keyPath isEqualToString:@"loadedTimeRanges"]) {
            
            // 计算缓冲进度
            NSTimeInterval timeInterval = [self availableDuration];
            CMTime duration             = self.playerItem.duration;
            CGFloat totalDuration       = CMTimeGetSeconds(duration);
            
            [self.controlView zf_playerSetProgress:timeInterval / totalDuration];
            
        } else if ([keyPath isEqualToString:@"playbackBufferEmpty"]) {
            // 当缓冲是空的时候
            if (self.playerItem.playbackBufferEmpty) {
                self.state = ZFPlayerStateBuffering;
                [self bufferingSomeSecond];
            }
        } else if ([keyPath isEqualToString:@"playbackLikelyToKeepUp"]) {
            // 当缓冲好的时候
            if (self.playerItem.playbackLikelyToKeepUp && _state == ZFPlayerStateBuffering){
                self.state = ZFPlayerStatePlaying;
            }
        }
    } else if (context == (__bridge void *)[AVAudioSession sharedInstance]){
        if (self.isFullScreen) {
            [self.controlView zf_playerCancelAutoFadeOutVoiceView];
            CGFloat newValue = [[change objectForKey:@"new"] floatValue];
            //音量view的显示与隐藏
            [self.controlView zf_playerAutoFadeInThenOutVoiceView:newValue];
        }
    }
}

/**
 *  设置横屏的约束
 */
- (void)setOrientationLandscapeConstraint
{
    // 改为黑色的背景，不然站位图会显示
    UIImage *image = [self buttonImageFromColor:[UIColor blackColor]];
    self.layer.contents = (id) image.CGImage;
    // 亮度view加到window最上层
    ZFBrightnessView *brightnessView = [ZFBrightnessView sharedBrightnessView];
    [kKeyWindow insertSubview:self belowSubview:brightnessView];
    [kKeyWindow bringSubviewToFront:self];
    [self mas_remakeConstraints:^(MASConstraintMaker *make) {
        make.edges.insets(UIEdgeInsetsMake(0, 0, 0, 0));
    }];
}

/**
 *  设置竖屏的约束
 */
- (void)setOrientationPortraitConstraint
{
    [self removeFromSuperview];
    UITableViewCell * cell = [self.playerModel.tableView cellForRowAtIndexPath:self.playerModel.indexPath];
    // 根据tag取到对应的cellImageView
    UIImageView *cellImageView = [cell viewWithTag:self.playerModel.cellImageViewTag];
    /** player添加到cellImageView上 */
    [cellImageView addSubview:self];
    [self mas_remakeConstraints:^(MASConstraintMaker *make) {
        make.top.leading.trailing.bottom.equalTo(cellImageView);
    }];
}

#pragma mark 屏幕转屏相关

/**
 *  强制屏幕转屏
 *
 *  @param orientation 屏幕方向
 */
- (void)interfaceOrientation:(UIInterfaceOrientation)orientation
{
    // arc下
    if ([[UIDevice currentDevice] respondsToSelector:@selector(setOrientation:)]) {
        SEL selector             = NSSelectorFromString(@"setOrientation:");
        NSInvocation *invocation = [NSInvocation invocationWithMethodSignature:[UIDevice instanceMethodSignatureForSelector:selector]];
        [invocation setSelector:selector];
        [invocation setTarget:[UIDevice currentDevice]];
        int val                  = orientation;
        // 从2开始是因为0 1 两个参数已经被selector和target占用
        [invocation setArgument:&val atIndex:2];
        [invocation invoke];
    }
    if (orientation == UIInterfaceOrientationLandscapeRight || orientation == UIInterfaceOrientationLandscapeLeft) {
        // 设置横屏
        [self setOrientationLandscapeConstraint];
        
    } else if (orientation == UIInterfaceOrientationPortrait) {
        // 设置竖屏
        [self setOrientationPortraitConstraint];
        
    }
}

#pragma mark - 缓冲较差时候

/** 缓冲较差时候回调这里 */
- (void)bufferingSomeSecond
{
    self.state = ZFPlayerStateBuffering;
    // playbackBufferEmpty会反复进入，因此在bufferingOneSecond延时播放执行完之前再调用bufferingSomeSecond都忽略
    __block BOOL isBuffering = NO;
    if (isBuffering) return;
    isBuffering = YES;
    
    // 需要先暂停一小会之后再播放，否则网络状况不好的时候时间在走，声音播放不出来
    [self.player pause];
    __weak typeof(self) weakSelf = self;
    dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(1.0 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
        // 如果此时用户已经暂停了，则不再需要开启播放了
        if (weakSelf.isPauseByUser) {
            isBuffering = NO;
            return;
        }
        
        [weakSelf play];
        // 如果执行了play还是没有播放则说明还没有缓存好，则再次缓存一段时间
        isBuffering = NO;
        if (!weakSelf.playerItem.isPlaybackLikelyToKeepUp) { [weakSelf bufferingSomeSecond]; }
        
    });
}

#pragma mark - 计算缓冲进度

/**
 *  计算缓冲进度
 *
 *  @return 缓冲进度
 */
- (NSTimeInterval)availableDuration
{
    NSArray *loadedTimeRanges = [[_player currentItem] loadedTimeRanges];
    CMTimeRange timeRange     = [loadedTimeRanges.firstObject CMTimeRangeValue];// 获取缓冲区域
    float startSeconds        = CMTimeGetSeconds(timeRange.start);
    float durationSeconds     = CMTimeGetSeconds(timeRange.duration);
    NSTimeInterval result     = startSeconds + durationSeconds;// 计算缓冲总进度
    return result;
}

#pragma mark - Action

/** 轻拍方法 */
- (void)singleTapAction:(UIGestureRecognizer *)gesture
{
    /** 修改后方法 */
    if (_isFullScreen) {
        [self _fullScreenAction];
    } else {
        if (!_isLocalVideo && (![IGNetReachable isReachable] || _state == ZFPlayerStateFailed)) {
            return;
        }
        // 显示控制层
        [self.controlView zf_playerCancelAutoFadeOutControlView];
        [self.controlView zf_playerShowControlView];
        if (self.isPauseByUser) {
            [self play];
        } else {
            [self pause];
        }
    }
}

/**
 *  播放
 */
- (void)play
{
    if (_state == ZFPlayerStateBuffering) {
        [self.controlView zf_playerActivity:YES];
    }
    
    [self.controlView zf_playerPlayBtnState:YES];
    if (_state == ZFPlayerStatePause) {
        self.state = ZFPlayerStatePlaying;
    }
    self.isPauseByUser = NO;
    [_player play];
    // 显示控制层
    [self.controlView zf_playerCancelAutoFadeOutControlView];
    [self.controlView zf_playerShowControlView];
}

/**
 * 暂停
 */
- (void)pause
{
    [self.controlView zf_playerActivity:NO];
    [self.controlView zf_playerPlayBtnState:NO];
    if (_state == ZFPlayerStatePlaying) { self.state = ZFPlayerStatePause;}
    self.isPauseByUser = YES;
    [_player pause];
}

/** 全屏 */
- (void)_fullScreenAction
{
    //全屏按钮下隐藏电量条按钮
    if (self.fullScreenBlock) {
        self.fullScreenBlock(!self.isFullScreen);
    }

    if (self.isFullScreen) {//全屏--->非全屏

        [self interfaceOrientation:UIInterfaceOrientationPortrait];
        NSDictionary *dic = @{KVideoFullScreenNotification:@(self.isFullScreen)};
        self.isFullScreen = !self.isFullScreen;
        [[NSNotificationCenter defaultCenter] postNotificationName:KVideoFullScreenNotification object:dic];
        return;
    }

    //非全屏--->全屏
    NSDictionary *dic = @{KVideoFullScreenNotification:@(self.isFullScreen)};
    self.isFullScreen = !self.isFullScreen;
    [[NSNotificationCenter defaultCenter] postNotificationName:KVideoFullScreenNotification object:dic];
    UIDeviceOrientation orientation = [UIDevice currentDevice].orientation;
    UIInterfaceOrientation interfaceOrientation = (UIInterfaceOrientation)orientation;
    switch (interfaceOrientation) {
        case UIInterfaceOrientationPortrait:{
            [self interfaceOrientation:UIInterfaceOrientationLandscapeRight];
        }
            break;
        case UIInterfaceOrientationLandscapeLeft:{
            [self interfaceOrientation:UIInterfaceOrientationLandscapeLeft];
        }
            break;
        case UIInterfaceOrientationLandscapeRight:{
            [self interfaceOrientation:UIInterfaceOrientationLandscapeRight];
        }
            break;
            
        default: {
            [self interfaceOrientation:UIInterfaceOrientationLandscapeRight];
        }
            break;
    }
    
}

#pragma mark - NSNotification Action

/** 播放完了 */
- (void)moviePlayDidEnd:(NSNotification *)notification
{
    [self seekToTime:0 completionHandler:nil];
}

/** 应用退到后台 */
- (void)appDidEnterBackground
{
    self.didEnterBackground = YES;
    [_player pause];
    self.state = ZFPlayerStatePause;
}

/** 应用进入前台 */
- (void)appDidEnterPlayground
{
    self.didEnterBackground = NO;
    [self.controlView zf_playerShowControlView];
    if (!self.isPauseByUser) {
        if (!_isLocalVideo && (![IGNetReachable isReachable] || self.videoNetStatusing == LJVideoNetStatus4Ging)) {
            return;
        }
        self.state          = ZFPlayerStatePlaying;
        self.isPauseByUser  = NO;
        [self play];
    }
}

/**
 *  从xx秒开始播放视频跳转
 *
 *  @param dragedSeconds 视频跳转的秒数
 */
- (void)seekToTime:(NSInteger)dragedSeconds completionHandler:(void (^)(BOOL finished))completionHandler
{
    if (self.player.currentItem.status == AVPlayerItemStatusReadyToPlay) {
        // seekTime:completionHandler:不能精确定位
        // 如果需要精确定位，可以使用seekToTime:toleranceBefore:toleranceAfter:completionHandler:
        // 转换成CMTime才能给player来控制播放进度
        [self.controlView zf_playerActivity:YES];
        
        [self.player pause];
        CMTime dragedCMTime = CMTimeMake(dragedSeconds, 1); //kCMTimeZero
        __weak typeof(self) weakSelf = self;
        [self.player seekToTime:dragedCMTime toleranceBefore:CMTimeMake(1,1) toleranceAfter:CMTimeMake(1,1) completionHandler:^(BOOL finished) {
            [weakSelf.controlView zf_playerActivity:NO];
            // 视频跳转回调
            if (completionHandler) { completionHandler(finished); }
            [weakSelf.player play];
            weakSelf.seekTime = 0;
            // 结束滑动
            [weakSelf.controlView zf_playerDraggedEnd];
            if (!weakSelf.playerItem.isPlaybackLikelyToKeepUp && !weakSelf.isLocalVideo) {
                weakSelf.state = ZFPlayerStateBuffering;
            }
        }];
    }
}

#pragma mark - UIPanGestureRecognizer手势方法

/** pan手势事件 */
- (void)panDirection:(UIPanGestureRecognizer *)pan
{
    if (!_isFullScreen) {
        return;
    }
    if (![IGNetReachable isReachable] && !_isLocalVideo) {
        return;
    }
    // 显示控制层
    [self.controlView zf_playerCancelAutoFadeOutControlView];
    [self.controlView zf_playerShowControlView];
    //根据在view上Pan的位置，确定是调音量还是亮度
    CGPoint locationPoint = [pan locationInView:self];
    
    // 我们要响应水平移动和垂直移动
    // 根据上次和本次移动的位置，算出一个速率的point
    CGPoint veloctyPoint = [pan velocityInView:self];
    
    // 判断是垂直移动还是水平移动
    switch (pan.state) {
        case UIGestureRecognizerStateBegan:{ // 开始移动
            // 使用绝对值来判断移动的方向
            CGFloat x = fabs(veloctyPoint.x);
            CGFloat y = fabs(veloctyPoint.y);
            if (x > y) { // 水平移动
                // 取消隐藏
                self.panDirection = PanDirectionHorizontalMoved;
                // 给sumTime初值
                CMTime time       = self.player.currentTime;
                self.sumTime      = time.value/time.timescale;
            } else if (x < y){ // 垂直移动
                self.panDirection = PanDirectionVerticalMoved;
                // 开始滑动的时候,状态改为正在控制音量
                if (locationPoint.x > self.bounds.size.width / 2) {
                    self.isVolume = YES;
                }else { // 状态改为显示亮度调节
                    self.isVolume = NO;
                }
            }
            break;
        }
        case UIGestureRecognizerStateChanged:{ // 正在移动
            switch (self.panDirection) {
                case PanDirectionHorizontalMoved:{
                    [self horizontalMoved:veloctyPoint.x]; // 水平移动的方法只要x方向的值
                    break;
                }
                case PanDirectionVerticalMoved:{
                    [self verticalMoved:veloctyPoint.y]; // 垂直移动方法只要y方向的值
                    break;
                }
                default:
                    break;
            }
            break;
        }
        case UIGestureRecognizerStateEnded:{ // 移动停止
            // 移动结束也需要判断垂直或者平移
            // 比如水平移动结束时，要快进到指定位置，如果这里没有判断，当我们调节音量完之后，会出现屏幕跳动的bug
            switch (self.panDirection) {
                case PanDirectionHorizontalMoved:{
                    self.isPauseByUser = NO;
                    [self seekToTime:self.sumTime completionHandler:nil];
                    // 把sumTime滞空，不然会越加越多
                    self.sumTime = 0;
                    break;
                }
                case PanDirectionVerticalMoved:{
                    // 垂直移动结束后，把状态改为不再控制音量
                    self.isVolume = NO;
                    break;
                }
                default:
                    break;
            }
            break;
        }
        default:
            break;
    }
}

/**
 *  pan垂直移动的方法
 *
 *  @param value void
 */
- (void)verticalMoved:(CGFloat)value
{
    if (self.isVolume) {
        self.volumeViewSlider.value -= value / 10000;
    }
}

/**
 *  pan水平移动的方法
 *
 *  @param value void
 */
- (void)horizontalMoved:(CGFloat)value
{
    // 每次滑动需要叠加时间
    self.sumTime += value / 200;
    
    // 需要限定sumTime的范围
    CMTime totalTime           = self.playerItem.duration;
    CGFloat totalMovieDuration = (CGFloat)totalTime.value/totalTime.timescale;
    if (self.sumTime > totalMovieDuration) { self.sumTime = totalMovieDuration;}
    if (self.sumTime < 0) { self.sumTime = 0; }
    
    BOOL style = false;
    if (value > 0) { style = YES; }
    if (value < 0) { style = NO; }
    if (value == 0) { return; }
    
    [self.controlView zf_playerDraggedTime:self.sumTime totalTime:totalMovieDuration isForward:style hasPreview:NO];
}

#pragma mark - UIGestureRecognizerDelegate

- (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldReceiveTouch:(UITouch *)touch
{
    if ([gestureRecognizer isKindOfClass:[UIPanGestureRecognizer class]]) {
        if (!self.isFullScreen){
            return NO;
        }
    }
    if ([touch.view isKindOfClass:[UISlider class]]) {
        return NO;
    }
    
    return YES;
}

#pragma mark - Others

/**
 *  通过颜色来生成一个纯色图片
 */
- (UIImage *)buttonImageFromColor:(UIColor *)color
{
    CGRect rect = self.bounds;
    UIGraphicsBeginImageContext(rect.size);
    CGContextRef context = UIGraphicsGetCurrentContext();
    CGContextSetFillColorWithColor(context, [color CGColor]);
    CGContextFillRect(context, rect);
    UIImage *img = UIGraphicsGetImageFromCurrentImageContext();
    UIGraphicsEndImageContext(); return img;
}

#pragma mark - Setter

/** 设置播放的状态 */
- (void)setState:(ZFPlayerState)state
{
    _state = state;
    // 控制菊花显示、隐藏
    [self.controlView zf_playerActivity:state == ZFPlayerStateBuffering];
    if (state == ZFPlayerStatePlaying) {
        // 改为黑色的背景，不然站位图会显示
        UIImage *image = [self buttonImageFromColor:[UIColor blackColor]];
        self.layer.contents = (id) image.CGImage;
    } else if (state == ZFPlayerStateFailed) {
        NSError *error = [self.playerItem error];
        [self.controlView zf_playerItemStatusFailed:error];
    }
}

/**
 *  根据playerItem，来添加移除观察者
 *
 *  @param playerItem playerItem
 */
- (void)setPlayerItem:(AVPlayerItem *)playerItem
{
    if (_playerItem == playerItem) {return;}
    
    if (_playerItem) {
        [[NSNotificationCenter defaultCenter] removeObserver:self name:AVPlayerItemDidPlayToEndTimeNotification object:_playerItem];
        [_playerItem removeObserver:self forKeyPath:@"status"];
        [_playerItem removeObserver:self forKeyPath:@"loadedTimeRanges"];
        [_playerItem removeObserver:self forKeyPath:@"playbackBufferEmpty"];
        [_playerItem removeObserver:self forKeyPath:@"playbackLikelyToKeepUp"];
    }
    _playerItem = playerItem;
    if (playerItem) {
        [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(moviePlayDidEnd:) name:AVPlayerItemDidPlayToEndTimeNotification object:playerItem];
        [playerItem addObserver:self forKeyPath:@"status" options:NSKeyValueObservingOptionNew context:nil];
        [playerItem addObserver:self forKeyPath:@"loadedTimeRanges" options:NSKeyValueObservingOptionNew context:nil];
        // 缓冲区空了，需要等待数据
        [playerItem addObserver:self forKeyPath:@"playbackBufferEmpty" options:NSKeyValueObservingOptionNew context:nil];
        // 缓冲区有足够数据可以播放了
        [playerItem addObserver:self forKeyPath:@"playbackLikelyToKeepUp" options:NSKeyValueObservingOptionNew context:nil];
    }
}

- (void)setControlView:(LJZFPlayerControlView *)controlView
{
    _controlView = controlView;
    controlView.delegate = self;
    [self addSubview:controlView];
    [controlView mas_makeConstraints:^(MASConstraintMaker *make) {
        make.top.leading.trailing.bottom.equalTo(self);
    }];
}

- (void)setPlayerModel:(ZFPlayerModel *)playerModel
{
    _playerModel = playerModel;
    
    if (self.playerModel.placeholderImage) {
        self.layer.contents = (id) self.playerModel.placeholderImage.CGImage;
    }
    // 添加通知
    [self addNotifications];
    self.isPauseByUser = YES;
    
    // 添加手势
    [self createGesture];
    // 在cell播放
    [self.controlView zf_playerCellPlay];
}

#pragma mark - Getter

- (UISlider *)volumeViewSlider
{
    if (!_volumeViewSlider) {
        _volumeViewSlider = [[UISlider alloc] initWithFrame:CGRectMake(-1000, -1000, 100, 100)];
    }
    return _volumeViewSlider;
}

- (AVAssetImageGenerator *)imageGenerator
{
    if (!_imageGenerator) {
        _imageGenerator = [AVAssetImageGenerator assetImageGeneratorWithAsset:self.urlAsset];
    }
    return _imageGenerator;
}

#pragma mark - ZFPlayerControlViewDelegate

- (void)zf_controlView:(UIView *)controlView playAction:(UIButton *)sender
{
    // 显示控制层
    [self.controlView zf_playerCancelAutoFadeOutControlView];
    [self.controlView zf_playerShowControlView];
    
    self.isPauseByUser = !self.isPauseByUser;
    if (self.isPauseByUser) {
        [self pause];
        if (_state == ZFPlayerStatePlaying) {
            self.state = ZFPlayerStatePause;
        }
    } else {
        [self play];
        if (_state == ZFPlayerStatePause) {
            self.state = ZFPlayerStatePlaying;
        }
    }
}

- (void)zf_controlView:(UIView *)controlView fullScreenAction:(UIButton *)sender
{
    [self _fullScreenAction];
}

/** 加载失败按钮事件 */
- (void)zf_controlView:(UIView *)controlView failAction:(UIButton *)sender
{
    [self configZFPlayer];
}

- (void)zf_controlView:(UIView *)controlView progressSliderTap:(CGFloat)value
{
    // 视频总时间长度
    CGFloat total = (CGFloat)self.playerItem.duration.value / self.playerItem.duration.timescale;
    //计算出拖动的当前秒数
    NSInteger dragedSeconds = floorf(total * value);
    
    [self.controlView zf_playerPlayBtnState:YES];
    [self seekToTime:dragedSeconds completionHandler:^(BOOL finished) {}];
    
}

- (void)zf_controlView:(UIView *)controlView progressSliderValueChanged:(UISlider *)slider
{
    // 显示控制层
    [self.controlView zf_playerCancelAutoFadeOutControlView];
    [self.controlView zf_playerShowControlView];
    // 拖动改变视频播放进度
    if (self.player.currentItem.status == AVPlayerItemStatusReadyToPlay) {
        
        BOOL style = false;
        CGFloat value   = slider.value - self.sliderLastValue;
        if (value > 0) { style = YES; }
        if (value < 0) { style = NO; }
        if (value == 0) { return; }
        
        self.sliderLastValue  = slider.value;
        
        CGFloat totalTime     = (CGFloat)_playerItem.duration.value / _playerItem.duration.timescale;
        
        //计算出拖动的当前秒数
        CGFloat dragedSeconds = floorf(totalTime * slider.value);
        [controlView zf_playerDraggedTime:dragedSeconds totalTime:totalTime isForward:style hasPreview:NO];
    } else { // player状态加载失败
        // 此时设置slider值为0
        slider.value = 0;
    }
}

- (void)zf_controlView:(UIView *)controlView progressSliderTouchEnded:(UISlider *)slider
{
    if (self.player.currentItem.status == AVPlayerItemStatusReadyToPlay) {
        self.isPauseByUser = NO;
        // 视频总时间长度
        CGFloat total           = (CGFloat)_playerItem.duration.value / _playerItem.duration.timescale;
        //计算出拖动的当前秒数
        NSInteger dragedSeconds = floorf(total * slider.value);
        [self seekToTime:dragedSeconds completionHandler:nil];
    }
}

#pragma mark - 网络状态判断
- (void)reachabilityChanged:(id)notification
{
    NSString *isStartWith4G = @"0";
    if ([notification isKindOfClass:[NSString class]]) {
        isStartWith4G = @"1";
    }
    if (![IGNetReachable isReachable]) {
        
        [self.player pause];
        self.state = ZFPlayerStatePause;
        self.videoNetStatusing = LJVideoNetStatusNoWifiing;
        //隐藏加载旋转图标
        [self.controlView zf_playerActivity:NO];
        [self.controlView zf_playerPlayeBtnHidden:YES];
        
        [self.controlView zf_playerNetStatusViewHidden:NO];
        [self.controlView netStatusViewTips:NSLocalizedString(@"Your WIFI Disconnected.", nil) btnTitle:NSLocalizedString(@"Try Again", nil) btnBlock:nil];
        return;
    } else if ([IGNetReachable isReachable]) {
        AFNetworkReachabilityStatus status = [IGNetReachable status];
        if (status == AFNetworkReachabilityStatusReachableViaWWAN) {
            if (![[NSUserDefaults standardUserDefaults] objectForKey:@"isFirstChangeToWWAN"]) {
                [self.player pause];
                self.state = ZFPlayerStatePause;
                self.videoNetStatusing = LJVideoNetStatus4Ging;
                if (!_isFullScreen) {
                    [self.controlView zf_playerPlayeBtnHidden:YES];
                }
                
                [self.controlView zf_playerNetStatusViewHidden:NO];
                self.singleTap.enabled = NO;
                NSString *netStatusTips = NSLocalizedString(@"Switched to 2G/3G/4G Network", nil);
                if ([isStartWith4G isEqualToString:@"1"]) {
                    netStatusTips = NSLocalizedString(@"You Are Appreciating with Your Mobile Phone Data", nil);
                }
                __weak typeof(self) weakSelf = self;
                [self.controlView netStatusViewTips:netStatusTips btnTitle:NSLocalizedString(@"Continue to Appreciate with Mobile Phone Data", nil) btnBlock:^{
                    [[NSUserDefaults standardUserDefaults] setObject:@"1" forKey:@"isFirstChangeToWWAN"];
                    weakSelf.singleTap.enabled = YES;
                    [weakSelf.controlView zf_playerNetStatusViewHidden:YES];
                    [weakSelf.controlView zf_playerShowControlView];
                    weakSelf.videoNetStatusing = LJVideoNetStatusNormal;
                    if (!weakSelf.isPauseByUser) {
                        weakSelf.state          = ZFPlayerStatePlaying;
                        weakSelf.isPauseByUser  = NO;
                        [weakSelf play];
                        if (!weakSelf.isFullScreen) {
                            [weakSelf.controlView zf_playerPlayeBtnHidden:YES];
                        }
                    } else {
                        if (!weakSelf.isFullScreen) {
                            [weakSelf.controlView zf_playerPlayeBtnHidden:NO];
                        }
                    }
                }];
            }
        } else if (status == AFNetworkReachabilityStatusReachableViaWiFi) {
            if ([isStartWith4G isEqualToString:@"1"]) {
                return;
            }
            self.singleTap.enabled = YES;
            self.videoNetStatusing = LJVideoNetStatusNormal;
            [self.controlView zf_playerNetStatusViewHidden:YES];
            [self.controlView zf_playerShowControlView];
            if (!self.isFullScreen) {
                if (self.state == ZFPlayerStatePause) {
                    [self.controlView zf_playerPlayeBtnHidden:NO];
                }
            }
            
            if (!self.isPauseByUser) {
                self.state          = ZFPlayerStatePlaying;
                self.isPauseByUser  = NO;
                [self play];
            }
        }
    }
}

@end
